#!/usr/bin/env python
# -*- coding: utf-8 -*-
#===============================================================================
# Copyright 2011 zod.yslin
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# 
# Author: zod.yslin
# Email: 
# File Name: iterator.py
# Description: 
#   iterator protocol 使得我们可以对不同的容器（其实是任何支持遍历操作的对象，
#   不一定是用来存放数据的容器）使用相同的方式（for 语句）进行遍历。
#   容器可以是 list, dictionary 或者是其他用户定义的数据结构，它只需要实现 
#   __iter__()方法，返回一个 iterator object 即可。
#   真正关心如何遍历的是 iterator object，它的两个方法构成了 iterator protocol。
#        1. __iter__() 返回自身
#        2. next() 返回容器中的下一个对象，没有更多对象时应 raise
#           StopIteration，一旦抛出此异常，后续的调用一定也必须抛出此异常。
# Edit History: 
#   2011-10-18    File created.
#===============================================================================
# Iterator Types http://docs.python.org/library/stdtypes.html#iterator-types
class countdown(object):
    "iterator object"
    def __init__(self, start):
        self.count = start
    def __iter__(self):
        return self
    def next(self):
        if self.count <= 0:
            raise StopIteration
        r = self.count
        self.count -= 1
        return r

cd = countdown(2)
_iter = cd.__iter__() # Get iterator object
while 1:
    try:
        x = _iter.next() # Get next item
        print x
    except StopIteration: # No more items
        break

# syntax sugar
cd = countdown(2)
 
for i in cd:
   print i

# Generator Types http://docs.python.org/library/stdtypes.html#generator-types
class countdown():
    "container"
    def __init__(self, start):
        self.count = start
    def __iter__(self):
        """
        一旦在函数定义中使用 yield，这个函数就成为 generator function 而不是普通的函数。 
        generator function 被调用时会返回 generator iterator，简称 generator。
        调用 generator 的 next() 方法时，generator function 的函数体会执行，
        当遇到 yield 时，generator 的状态会冻结，而当前值被返回
        """
        it = self.count
        while it > 0:
            yield it
            it -= 1
"""
lazy evaluation, generator 的其他用处

利用 generator 可以模拟出 lazy evaluation 来。lazy evaluation 我觉得最有用的地方在于，
    1.使用管道风格的代码处理数据时，避免产生大量临时的结果，提高性能
    2.处理无限长度的数据
    3.避免不必要的求值
但 generator 不光可以用来处理数据，Beazley 的幻灯片里提到 networking, threads, co-routines 等都可以用 generator 来处理。
"""

cd = countdown(2)
 
for i in cd:
   print i
